#ifndef _GENTHREADS_
#define _GENTHREADS_

#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <numeric>
#include <functional>
#include <algorithm>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/timer.hpp>
#include <boost/bind.hpp>
#include "utils.h"

using std::vector;
using std::endl;
using std::cout;
using std::cerr;

class scoped_timer {
    boost::posix_time::ptime start_;
    std::string m_text;
public:    
    inline  void   SetText(std::string text){m_text=text;};
    scoped_timer(std::string text) 
      : start_(boost::posix_time::microsec_clock::universal_time()),m_text(text)
    {
      m_start= getticks();
    }
    ~scoped_timer() {
      
		boost::posix_time::ptime stop( boost::posix_time::microsec_clock::universal_time() );
		m_end=getticks();
		double clock_cycles=elapsed(m_end, m_start);
		std::cout<<std::setprecision(2)<<std::fixed;
		std::cout <<" "<<m_text<< " done in " << ( stop - start_).total_milliseconds() << " milli seconds or "<<clock_cycles<<" CPU cycles ";
		 my_mem_usage();
    }
 protected:
    ticks m_start;
    ticks m_end;
};
// 4.2 How to Implement Functors
// abstract base class
class TFunctor
	{
	public:

		// two possible functions to call member function. virtual cause derived
		// classes will use a pointer to an object and a pointer to a member function
		// to make the function call
		virtual void operator()(const char* string)=0;  // call using operator
		virtual void Call(const char* string)=0;        // call using function
		virtual void Run(const int ia, const int ib)=0;        // call using function
		bool verbose_flag;
	};
// derived template class
template <class TClass> class TSpecificFunctor : public TFunctor
	{
	private:
		void (TClass::*fpt)(const char*);   // pointer to member function
		void (TClass::*fpt1)(const int ia, const int ib);   // pointer to member function
		TClass* pt2Object;                  // pointer to object
		
	public:

		// constructor - takes pointer to an object and pointer to a member and stores
		// them in two private variables
		TSpecificFunctor(TClass* _pt2Object, void(TClass::*_fpt)(const char*)):fpt1(NULL)
			{ pt2Object = _pt2Object;  fpt = _fpt; verbose_flag=false;};
		TSpecificFunctor(TClass* _pt2Object, void(TClass::*_fpt1)(const int ia, const int ib)):fpt(NULL)
			{ pt2Object = _pt2Object;  fpt1 = _fpt1; verbose_flag=false;};

		// override operator "()"
		virtual void operator()(const char* string)
			{ 
				if(fpt!=NULL)
					(*pt2Object.*fpt)(string);
				else
					if(verbose_flag)
						cout<<"Warning operator ()(const char* string) not implemented!!!"<< endl;
			};              // execute member function

		// override function "Call"
		virtual void Call(const char* string)
			{ 
			if(fpt!=NULL)
				(*pt2Object.*fpt)(string);
			else
				if(verbose_flag)
					std::cout<<"Warning operator ()(const char* string) not implemented!!!"<< endl;
			};              // execute member function

		// override function "Call"
		virtual void Run(const int ia, const int ib)
			{ 
			if(fpt1!=NULL)
				(*pt2Object.*fpt1)(ia, ib);
			else
				if(verbose_flag)
					std::cout<<"Warning Function void Run(const int ia, const int ib) not implemented!!!"<< endl;
			};             // execute member function
	};

extern boost::mutex io_mutex;
class CGenThreads
	{
	public:
		CGenThreads(unsigned short dsize=1);
		~CGenThreads(void);
		int parallel_do_RUN(TFunctor* pObj, int istart, int iend,const char *analysistype="");
		static void RunInParallel(TFunctor* pObj,int a, int b, unsigned short  thrID)
			{
			pObj->Run(a, b);
				{
				//boost::mutex::scoped_lock scoped_lock(io_mutex);
				//std::cout<<"\n****  thread: ->  "<<thrID<<" ****"<<a<<" <==> "<<b<<endl;
				}
			}
		
		void Display(const char* text) 
			{ 
				{
				boost::mutex::scoped_lock scoped_lock(io_mutex);
				cout<< "Inside CGenThreads::Display: "<< text << endl; 
				}
			};
		
		template <typename T> 
		struct func
		{
			func(int StartIndex):m_index(StartIndex){};
			T operator () (const T val)const { return (T)m_index*5+val;}; 
			int m_index;
		};
		void do_parallel_on_ID(int a, int b) 
			{ 
				{
				//boost::mutex::scoped_lock scoped_lock(io_mutex);
				//cout<< "Inside CGenThreads::do_parallel_on_ID: " << a<<" <-> "<< b << endl; 
				}
				vector<float>::iterator ib=m_data.begin();
				vector<float>::iterator ie=ib;
				vector<float>::iterator it=m_data.end();;
				std::advance(ib, a);
				std::advance(ie, b);
				std::transform(ib,
						ie,ib,func<float>(a));

			};
		void do_parallel_on_SNAPS(int snapa, int snapb) 
			{ 
				{
				//boost::mutex::scoped_lock scoped_lock(io_mutex);
				//cout<< "Inside CGenThreads::do_parallel_on_SNAPS: " << snapa<<" <-> "<< snapb << endl;  
				}
			};
		void FillData()
		  {	
		    int seed = 10000;		/* choose a seed value */
		    //			unsigned int isize=GetDataSize();
		    srand(seed);		/*initialize random number generator*/
			std::generate(m_data.begin(), m_data.end(),rand);
			/* for( unsigned int i=0;i<isize;i++)
					{
					m_data[i]=rand()/float(RAND_MAX) ;
					}; 
*/
		  }
		void SetNumberOfThreads(unsigned short cpus){ NUM_CPU=cpus;};
		unsigned short GetNumberOfThreads(void ){ return NUM_CPU;};
		unsigned int GetDataSize(){return m_data.size();}
		void WriteData(void)
		  {
		    char buf[200];
		    sprintf(buf, "%04d.txt", NUM_CPU);
		    std::ofstream fo(buf);
			unsigned int isize=GetDataSize();
		    for( unsigned int i=0;i<isize;i++)
		      {
			fo<<std::setw(20)<<std::setprecision(5)<<
			  i<<"\t"<<m_data[i]<<endl;
		      }
		    fo.close();
		  }
		
	private:
		vector<float> m_data;				
		unsigned short  NUM_CPU;
	protected:
		bool m_verbose;

		
	};
#endif

